﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using QuadRemote.Core;
using System.Xml;

namespace QuadRemote
{
    public class LogValueGraph
    {
        public Pen pen;

        public bool axis;
        
        public LogValueContainer container;
        public int containerValue;

        public PointF[] points;
        
        public PointF hoverValue;

        // used for autoscaling
        public float minInPoints;
        public float maxInPoints;

        // used for redrawing
        int prevStartTime = -1;
        int prevEndTime = -1;
        float prevTimePerPixel = 0;
        int prevMaxTimestamp = 0;
        Boolean prevCalcAverage = false;

        public LogValueGraph(LogValueContainer container, int index, int width, Color color)
        {
            this.container = container;
            this.containerValue = index;
            points = new PointF[width];

            pen = new Pen(color);

            axis = false;
        }

        public LogValueGraph(XmlNode n, int width)
        {
            String name = n.SelectSingleNode("name").InnerText;

            foreach (LogValueContainer c in FlightSession.current().Log.values.Values)
            {
                if (c.name == name)
                {
                    this.container = c;
                    break;
                }
            }
            if (this.container == null) throw new Exception();

            int index = int.Parse(n.SelectSingleNode("index").InnerText);
            int r = int.Parse(n.SelectSingleNode("r").InnerText);
            int g = int.Parse(n.SelectSingleNode("g").InnerText);
            int b = int.Parse(n.SelectSingleNode("b").InnerText);
            int a = int.Parse(n.SelectSingleNode("a").InnerText);
            
            this.containerValue = index;
            points = new PointF[width];

            pen = new Pen(Color.FromArgb(a, r, g, b));

            axis = n.SelectSingleNode("axis").InnerText == "1";
        }

        public XmlElement save(XmlDocument root)
        {
            XmlElement node = root.CreateElement("plot");
            node.AppendChild(root.CreateElement("name")).InnerText = container.name;
            node.AppendChild(root.CreateElement("index")).InnerText = containerValue.ToString();
            node.AppendChild(root.CreateElement("a")).InnerText = pen.Color.A.ToString();
            node.AppendChild(root.CreateElement("r")).InnerText = pen.Color.R.ToString();
            node.AppendChild(root.CreateElement("g")).InnerText = pen.Color.G.ToString();
            node.AppendChild(root.CreateElement("b")).InnerText = pen.Color.B.ToString();
            node.AppendChild(root.CreateElement("axis")).InnerText = axis ? "1" : "0";
            return node;
        }

        public void resize(int width)
        {
            if (width <= 0) return;
            points = new PointF[width];
        }

        public void setColor(Color color)
        {
            pen.Color = color;
        }


        public int benchCounter = 0;

        public void redraw(int startTime, int endTime, float timePerPixel, int hoverTime, bool calculateAverage)
        {
            if (container.Count == 0) return;

            if (startTime != prevStartTime ||
                endTime != prevEndTime ||
                timePerPixel != prevTimePerPixel ||
                (container.maxTimestamp != prevMaxTimestamp && endTime > prevMaxTimestamp) ||
                prevCalcAverage != calculateAverage
                )
            {
                maxInPoints = float.MinValue;
                minInPoints = float.MaxValue;

                benchCounter = 0;

                int p = 0;

                if (calculateAverage)
                {
                    int i = container.findTimestamp(startTime);
                    int px = (int)((float)(container[i].timestamp - startTime) * timePerPixel);
                    int x;
                    int cdiv = 0;
                    float v = 0;

                    while (container[i].timestamp <= endTime + 1)
                    {
                        x = (int)((float)(container[i].timestamp - startTime) * timePerPixel);
                        benchCounter++;

                        if (x != px)
                        {
                            points[p].X = px;
                            points[p].Y = (v / (float)cdiv);

                            if (points[p].Y > maxInPoints) maxInPoints = points[p].Y;
                            if (points[p].Y < minInPoints) minInPoints = points[p].Y;

                            p++;
                            if (p == points.Length) break;

                            if (timePerPixel >= 2)
                            {
                                points[p].X = x;
                                points[p].Y = points[p - 1].Y;
                                p++;
                                if (p == points.Length) break;
                            }
                            cdiv = 0;
                            v = 0;
                            px = x;
                        }

                        v += container[i].payload[containerValue];
                        cdiv++;
                        i++;
                        if (i >= container.Count) break;
                    }

                }
                else
                {
                    for (int x = 0; x < points.Length; x+=4)
                    {
                        int time = (int)(startTime + x / timePerPixel);
                        int index = container.findTimestamp(time);
                        points[p].X = x;
                        points[p].Y = container[index].payload[containerValue];

                        if (points[p].Y > maxInPoints) maxInPoints = points[p].Y;
                        if (points[p].Y < minInPoints) minInPoints = points[p].Y;

                        p++;
                    }
                }


                // fill the rest of the points...
                if (p == 0)
                {
                    points[0].X = 0;
                    points[0].Y = 0;
                    p = 1;
                }
                for (int i = p; i < points.Length; i++)
                {
                    points[i].X = points[p - 1].X;
                    points[i].Y = points[p - 1].Y;
                }

                prevEndTime = endTime;
                prevMaxTimestamp = container.maxTimestamp;
                prevStartTime = startTime;
                prevTimePerPixel = timePerPixel;
                prevCalcAverage = calculateAverage;
            }

            if (hoverTime != -1)
            {
                int i = container.findTimestamp(hoverTime);
                hoverValue = new PointF(container[i].timestamp, container[i].payload[containerValue]);
            }
        }
    }
}
